#region Using References

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;

#endregion

namespace Beaker.OpenCube.Textures
{
	public struct FrameInfo
	{
		private readonly int _frameIndex;
		private readonly int _frameRepeatCount;

		public FrameInfo( int index, int repeatCount = 1 )
		{
			Contract.Requires<ArgumentOutOfRangeException>( index >= 0, "index must be positive" );
			Contract.Requires<ArgumentOutOfRangeException>( repeatCount >= 1, "repeat count must be at least 1" );
			Contract.Ensures( Contract.ValueAtReturn( out  _frameIndex ) == index );
			Contract.Ensures( Contract.ValueAtReturn( out  _frameRepeatCount ) == repeatCount );

			_frameIndex = index;
			_frameRepeatCount = repeatCount;
		}

		[ContractInvariantMethod]
		private void ContractInvariant()
		{
			Contract.Invariant( _frameIndex >= 0 );
			Contract.Invariant( _frameRepeatCount >= 1 );
		}

		/// <summary>
		/// Gets the index of the frame.
		/// </summary>
		/// <value>
		/// The index of the frame.
		/// </value>
		public int FrameIndex
		{
			get { return _frameIndex; }
		}

		/// <summary>
		/// Gets the frame repeat count.
		/// </summary>
		/// <value>
		/// The frame repeat count.
		/// </value>
		public int FrameRepeatCount
		{
			get { return _frameRepeatCount; }
		}

		public static bool TryParse( string frameInfoText, out IEnumerable<FrameInfo> frameInfoSequence )
		{
			Contract.Requires<ArgumentNullException>( frameInfoText != null );
			Contract.Ensures( Contract.Result<bool>() || Contract.ValueAtReturn( out frameInfoSequence ) == null );

			frameInfoSequence = null;

			// special case, empty file is valid empty parse
			if( string.IsNullOrWhiteSpace( frameInfoText ) )
				return true;

			var frameInfo = new List<FrameInfo>();

			// split on newline or comma
			string[] frames = frameInfoText.Split( new[] { ',', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries );
			foreach( string frame in frames )
			{
				// find * sign
				int ix = frame.IndexOf( '*' );

				if( ix == -1 )
				{
					// only frame index number

					int frameIndex;
					if( !int.TryParse( frame, NumberStyles.Integer, CultureInfo.InvariantCulture, out frameIndex ) )
						return false;

					frameInfo.Add( new FrameInfo( frameIndex ) );
				}
				else
				{
					// frame index before *
					// and frame count after *

					int frameIndex;
					int frameRepeat;

					if( !int.TryParse( frame.Substring( 0, ix ), NumberStyles.Integer, CultureInfo.InvariantCulture, out frameIndex ) )
						return false;
					if( !int.TryParse( frame.Substring( ix + 1 ), NumberStyles.Integer, CultureInfo.InvariantCulture, out frameRepeat ) )
						return false;

					frameInfo.Add( new FrameInfo( frameIndex, frameRepeat ) );
				}
			}

			frameInfoSequence = frameInfo.ToArray();
			return true;
		}
	}
}